package com.sh.data.engine.web.webapi.controller.integration;

import com.sh.data.engine.application.model.dto.base.PagerResponse;
import com.sh.data.engine.application.model.dto.common.DirectoryResponse;
import com.sh.data.engine.application.model.dto.integration.*;
import com.sh.data.engine.application.model.dto.workspace.UserResponse;
import com.sh.data.engine.application.model.request.common.UpsertDirectoryRequest;
import com.sh.data.engine.application.model.request.integration.CreateSyncTaskRequest;
import com.sh.data.engine.application.model.request.integration.OfflineSyncRequest;
import com.sh.data.engine.application.model.request.integration.OfflineTaskExistTableMappingRequest;
import com.sh.data.engine.application.service.integration.OfflineSyncApplicationService;
import com.sh.data.engine.common.annotation.fuzzyQuery.FuzzyMethod;
import com.sh.data.engine.common.enumDefinition.ProjectStatisticTypeEnum;
import com.sh.data.engine.domain.annotation.LogExecution;
import com.sh.data.engine.domain.annotation.ProjectStatisticExecution;
import com.sh.data.engine.domain.annotation.userlog.Business;
import com.sh.data.engine.domain.annotation.userlog.EngineOperation;
import com.sh.data.engine.domain.shims.db.model.PreviewDataDomain;
import com.sh.data.engine.web.webapi.controller.base.response.RestResponseEntity;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;

/**
 * @author binghe.yxh
 */
@RestController(value = "OfflineController")
@RequestMapping("/integration/offline")
@Tag(
    name = "数据集成-离线同步",
    description = "数据集成-离线同步API")
@Slf4j
public class OfflineSyncController {

    @Autowired
    private OfflineSyncApplicationService offlineSyncApplicationService;

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "获取数据库信息", description = "创建任务时选择来源和目标数据库的下拉列表")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/databases")
    public RestResponseEntity<List<OfflineSyncDatabaseResponse>> getOfflineSyncDatabases(
        @Parameter(description = "数据源来源 0-来源 1-目标", required = true) @RequestParam(value = "direction")
        Integer direction,
        @Parameter(description = "来源数据源id") @RequestParam(value = "dsId", required = false) String dsId) {
        var result = offlineSyncApplicationService.getOfflineSyncDatabases(direction, dsId);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "获取数据库表", description = "获取数据源表")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/tables")
    public RestResponseEntity<List<OfflineSyncTablesResponse>> getTables(
        @Parameter(description = "数据源id") @RequestParam(value = "dsId") Long dsId,
        @Parameter(description = "schema") @RequestParam(value = "schema", required = false) String schema,
        @Parameter(description = "数据源来源 0-来源 1-目标", required = true) @RequestParam(value = "direction")
        Integer direction) {
        var result = offlineSyncApplicationService.getOfflineSyncTables(direction, dsId, schema);
        return RestResponseEntity.success(result);
    }

    @Operation(summary = "查询数据库下所有schema", description = "查询数据库下所有schema")
    @GetMapping("/schema")
    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    public RestResponseEntity<List<String>> getSchemas(
        @Parameter(description = "数据源id") @RequestParam(value = "dsId") Long dsId,
        @Parameter(description = "数据源类型", required = true) @RequestParam(value = "dsType") String dsType) {
        var result = offlineSyncApplicationService.getSchemas(dsId, dsType);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "获取一键建表语句", description = "获取一键建表语句")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/getCreateTableSql")
    public RestResponseEntity<String> getCreateTableSql(
        @Parameter(description = "来源数据源id") @RequestParam(value = "dsId") Long dsId,
        @Parameter(description = "来源数据表名称") @RequestParam(value = "tableName") String tableName,
        @Parameter(description = "目标数据源id") @RequestParam(value = "targetDsId") Long targetDsId,
        @Parameter(description = "schema") @RequestParam(value = "schema", required = false) String schema,
        @Parameter(description = "infoCase")
        @RequestParam(value = "infoCase", required = false, defaultValue = "1")
        int infoCase) {
        var result = offlineSyncApplicationService.getCreateTableSql(dsId, tableName, targetDsId, schema, infoCase);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "执行一键建表语句", description = "执行一键建表语句")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.DATA_SYNC_CREATE_TABLE)
    @PostMapping("/executeCreateTableSql")
    @LogExecution(operation = EngineOperation.DATA_SYNC_CREATE_TABLE, business = Business.离线同步任务)
    @ProjectStatisticExecution(type = ProjectStatisticTypeEnum.TABLE)
    public RestResponseEntity<OfflineSyncCreateTableResponse> executeCreateTableSql(
        @Parameter(description = "目标数据源id") @RequestParam(value = "dsId") Long dsId,
        @Parameter(description = "SQL脚本", required = true) @RequestParam(value = "scripts") String scripts,
        @Parameter(description = "密级", required = false) @RequestParam(value = "dataSecretId", required = false) Long dataSecretId) {
        var result = offlineSyncApplicationService.executeCreateTableSql(dsId, scripts, dataSecretId);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "表和字段映射(已存在)", description = "表和字段映射(已存在)")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @PostMapping("/table/fields")
    public RestResponseEntity<OfflineTaskExistTableMappingResponse> getExistTablesMappings(
        @RequestBody OfflineTaskExistTableMappingRequest request) {
        var result = offlineSyncApplicationService.getExistTablesMappings(request);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "预览数据，返回最多10行记录", description = "预览数据，返回最多10行记录")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/previewData")
    public RestResponseEntity<PreviewDataDomain> previewData(
        @Parameter(description = "数据源id") @RequestParam(value = "dsId") Long dsId,
        @Parameter(description = "表名") @RequestParam(value = "tableName") String tableName) {
        var result = offlineSyncApplicationService.previewData(dsId, tableName);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "保存/编辑任务", description = "保存/编辑任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.ADD_UPDATE)
    @PostMapping(value = "/save")
    @ProjectStatisticExecution(type = ProjectStatisticTypeEnum.INTEGRATE_TASK_OFFLINE)
    @LogExecution(operation = EngineOperation.ADD_UPDATE, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> saveOfflineSyncTask(
        @Valid @RequestBody OfflineSyncRequest request) {
        var result = offlineSyncApplicationService.saveOfflineSyncTask(request);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "算盘组件编辑任务", description = "算盘组件编辑任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @PostMapping(value = "/saveSp")
    @ProjectStatisticExecution(type = ProjectStatisticTypeEnum.INTEGRATE_TASK_OFFLINE)
    @LogExecution(operation = EngineOperation.ADD_UPDATE, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> saveSpOfflineSyncTask(
        @RequestBody OfflineSyncRequest request) {
        var result = offlineSyncApplicationService.saveSpOfflineSyncTask(request);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "删除任务", description = "删除任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.DEL)
    @GetMapping("/delete")
    @ProjectStatisticExecution(type = ProjectStatisticTypeEnum.INTEGRATE_TASK_OFFLINE)
    @LogExecution(operation = EngineOperation.DEL, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> delOfflineSyncTask(
        @Parameter(description = "离线同步id") @RequestParam(value = "id") Long id) {
        var result = offlineSyncApplicationService.deleteOfflineSyncTask(id);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "离线同步任务详情", description = "离线同步任务性情")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/detail")
    public RestResponseEntity<OfflineSyncResponse> detail(
        @Parameter(description = "离线同步id", required = true) @RequestParam(value = "id") Long id) {
        var result = offlineSyncApplicationService.getDetail(id);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @GetMapping("/page")
    @Operation(summary = "获取离线同步任务列表")
    @FuzzyMethod(fuzzyParamIndex = 2)
    public RestResponseEntity<PagerResponse<OfflineSyncPageResponse>> getOfflineSyncTaskPage(
        @Parameter(description = "当前页", schema = @Schema(defaultValue = "1"))
        @RequestParam(required = false, defaultValue = "1")
        Integer pageNum,
        @Parameter(description = "每页大小", schema = @Schema(defaultValue = "10"))
        @RequestParam(required = false, defaultValue = "10")
        Integer pageSize,
        @Parameter(description = "任务名称") @RequestParam(required = false) String taskName,
        @Parameter(description = "运行状态") @RequestParam(required = false) String taskStatus,
        @Parameter(description = "发布状态") @RequestParam(required = false) Integer taskRunStatus,
        @Parameter(description = "负责人") @RequestParam(required = false) String creatorId,
        @Parameter(description = "开始时间")
        @RequestParam(required = false)
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        Date startTime,
        @Parameter(description = "结束时间")
        @RequestParam(required = false)
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        Date endTime,
        @Parameter(description = "目录ID") @RequestParam(required = false, defaultValue = "0") Long dirId,
        String order,
        String orderField,
        String cycle) {
        var result = offlineSyncApplicationService.getOfflineSyncTaskPage(
            pageNum, pageSize, taskName, taskStatus, taskRunStatus, creatorId, startTime, endTime, dirId, order, orderField, cycle);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @GetMapping("/statistics")
    @Operation(summary = "离线同步任务统计信息")
    public RestResponseEntity<OfflineSyncStatisticsResponse> statistics() {
        var result = offlineSyncApplicationService.queryStatistics();
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @GetMapping("/task/history")
    @Operation(summary = "历史任务")
    public RestResponseEntity<PagerResponse<OfflineSyncRunningRecordResponse>> historyTask(
        @Parameter(description = "当前页", schema = @Schema(defaultValue = "1"))
        @RequestParam(required = false, defaultValue = "1")
        Integer pageNum,
        @Parameter(description = "每页大小", schema = @Schema(defaultValue = "10"))
        @RequestParam(required = false, defaultValue = "10")
        Integer pageSize,
        @Parameter(description = "任务id") @RequestParam(required = true) Long taskId,
        @Parameter(description = "任务状态") @RequestParam(required = false) Integer taskStatus,
        @Parameter(description = "任务类型 0-周期 1-手动") @RequestParam(required = false) Integer executeType) {
        var result = offlineSyncApplicationService.historyTask(pageNum, pageSize, taskId, taskStatus, executeType);
        return RestResponseEntity.success(result);
    }

    /**
     * 发布任务
     *
     * @param taskId
     * @return
     */
    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "发布任务", description = "发布任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/online")
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.PUBLISH)
    @LogExecution(operation = EngineOperation.PUBLISH, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> online(
        @Parameter(description = "离线同步任务id") @RequestParam Long taskId) {
        var result = offlineSyncApplicationService.publishTask(taskId);
        return RestResponseEntity.success(result);
    }

    /**
     * 下线任务
     *
     * @param taskId
     * @return
     */
    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "下线任务", description = "下线任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/offline")
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.DEPUBLISH)
    @LogExecution(operation = EngineOperation.DEPUBLISH, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> offline(
        @Parameter(description = "离线同步任务id", required = true) @RequestParam Long taskId) {
        var result = offlineSyncApplicationService.offlineTask(taskId);
        return RestResponseEntity.success(result);
    }

    /**
     * 执行任务
     *
     * @param taskId
     * @return
     */
    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "执行任务", description = "执行任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/run")
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.START_TASK)
    @LogExecution(operation = EngineOperation.START_TASK, business = Business.离线同步任务)
    public RestResponseEntity<String> runTask(
        @Parameter(description = "离线同步任务id") @RequestParam Long taskId,
        @Parameter(description = "运行方式 1-试运行 0-重跑") @RequestParam Integer runType) {
        var result = offlineSyncApplicationService.runTask(taskId, runType);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "获取日志信息", description = "获取日志信息")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
    @GetMapping("/log")
    public RestResponseEntity<OfflineSyncLogResponse> getOfflineSyncLog(
        @Parameter(description = "离线同步任务LogId") @RequestParam Long logId,
        @Parameter(description = "偏移量", required = true) @RequestParam("offset") Integer offset) {
        var result = offlineSyncApplicationService.getOfflineSyncLog(logId, offset);
        return RestResponseEntity.success(result);
    }

    /**
     * 终止运行任务
     *
     * @param logId
     * @return
     */
    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "终止运行任务", description = "终止运行任务")
//    @ApiImplicitParams({
//        @ApiImplicitParam(
//            paramType = "header",
//            dataType = "String",
//            name = Constants.HEADER_PROJECT_ID,
//            value = "项目id标识",
//            required = true),
//    })
//    @Log(
//        business = Business.离线同步任务,
//        operation = Operation.STOP_TASK)
    @PostMapping("/stop")
    @LogExecution(operation = EngineOperation.STOP_TASK, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> stopTask(
        @Parameter(description = "离线同步任务id", required = true) @RequestParam("logId") String logId) {
        var result = offlineSyncApplicationService.stopTask(logId);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    @Operation(summary = "获取目录", description = "获取目录")
    @FuzzyMethod(fuzzyParamIndex = 0)
    @GetMapping("/getDirList")
    public RestResponseEntity<List<DirectoryResponse>> getDirList(
        @Parameter(description = "目录搜索") @RequestParam(value = "search", required = false) String search) {
        var result = offlineSyncApplicationService.getDirList(search);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "新增、更新目录", description = "新增、更新目录")
    @PostMapping("/upsetDir")
//    @Log(
//        business = Business.离线同步任务目录,
//        operation = Operation.ADD_UPDATE)
    @LogExecution(operation = EngineOperation.ADD_UPDATE, business = Business.离线同步任务目录)
    public RestResponseEntity<Boolean> upsetDir(@RequestBody UpsertDirectoryRequest request) {
        var result = offlineSyncApplicationService.upsetDir(request);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 1)
    @Operation(summary = "删除目录", description = "删除目录")
    @GetMapping("/deleteDir")
//    @Log(
//        business = Business.离线同步任务目录,
//        operation = Operation.DEL)
    @LogExecution(operation = EngineOperation.DEL, business = Business.离线同步任务目录)
    public RestResponseEntity<Boolean> deleteDir(Long id) {
        var result = offlineSyncApplicationService.deleteDir(id);
        return RestResponseEntity.success(result);
    }

    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE)
    @Operation(summary = "确定并同步数据", description = "确定并同步数据")
    @PostMapping("/saveAndDoSync")
    @ProjectStatisticExecution(type = ProjectStatisticTypeEnum.INTEGRATE_TASK_OFFLINE)
    @LogExecution(operation = EngineOperation.ADD_UPDATE, business = Business.离线同步任务)
    public RestResponseEntity<Boolean> saveAndDoSync(@RequestBody CreateSyncTaskRequest request) {
        var result = offlineSyncApplicationService.saveAndDoSync(request);
        return RestResponseEntity.success(result);
    }

    @Operation(summary = "查询用户信息列表")
    @GetMapping("/userList")
    // @AuthorityAnnotation(menuId = MenuEnumNew.RWGLOFFLINE, readWriteStatus = 0)
    public RestResponseEntity<List<UserResponse>> getUserList() {
        var result = offlineSyncApplicationService.getUserList();
        return RestResponseEntity.success(result);
    }
}
